package cnn.config;

import cnn.topfox.conf.MyBatisInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import javax.sql.DataSource;
import java.util.Collections;

@Configuration
@MapperScan(basePackages = MyBatisConfig.BASE_PACKAGE, sqlSessionFactoryRef = "hikariSqlSessionFactory")
public class MyBatisConfig {
    static final String BASE_PACKAGE = "cnn.*.dao";
    static final String ALIASES_PACKAGE = "cnn.*.entity";
    static final String MAPPER_LOCATION = "classpath*:mappers/*Mapper.xml";

    @Bean(name = "hikariSqlSessionFactory")
    @Primary
    public SqlSessionFactory hikariSqlSessionFactory(@Qualifier("hikariDataSource") DataSource dataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();//增加 MyBatis SQL拦截器
        sessionFactory.setPlugins(new Interceptor[] {new MyBatisInterceptor()});
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setTypeAliasesPackage(MyBatisConfig.ALIASES_PACKAGE);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MyBatisConfig.MAPPER_LOCATION));
        sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return sessionFactory.getObject();
    }

    @Bean(name = "hikariTransactionManager")
    @Primary
    public DataSourceTransactionManager hikariTransactionManager(@Qualifier("hikariDataSource") DataSource extensionDataSource) {
        return new DataSourceTransactionManager(extensionDataSource);
    }

    @Bean(name = "txAdvice")
    @Primary
    public TransactionInterceptor txAdvice(@Qualifier("hikariTransactionManager") DataSourceTransactionManager hikariTransactionManager) {
        RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
        required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        required.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);

        RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
        readOnly.setReadOnly(true);
        readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        //默认的只读事务配置
        for (String methodName : TransactionAttributeTemplate.REQUIRED_READONLY) {
            source.addTransactionalMethod(methodName, readOnly);
        }

        //默认的传播事务配置
        for (String methodName : TransactionAttributeTemplate.REQUIRED) {
            source.addTransactionalMethod(methodName, required);
        }

        //业务
        //source.addTransactionalMethod("upgrade*", required);
        //source.addTransactionalMethod("reward", required);

        return new TransactionInterceptor(hikariTransactionManager, source);
    }

    @Bean
    @Primary
    public BeanNameAutoProxyCreator txProxy() {
        BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
        //开启事务的 类名结尾字符定义
        creator.setInterceptorNames("txAdvice");
        creator.setBeanNames("*Service","*ServiceImpl");
        creator.setProxyTargetClass(true);
        return creator;
    }

}
